package org.quickserver.security;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.quickserver.swing.SensitiveInput;
import org.quickserver.util.xmlreader.ConfigReader;
import org.quickserver.util.xmlreader.KeyStoreInfo;
import org.quickserver.util.xmlreader.QuickServerConfig;
import org.quickserver.util.xmlreader.Secure;
import org.quickserver.util.xmlreader.SecureStore;
import org.quickserver.util.xmlreader.TrustStoreInfo;







public class SecureStoreManager
{
  private static Logger logger = Logger.getLogger(
      SecureStoreManager.class.getName());
  private SensitiveInput sensitiveInput = null;






  
  public KeyManager[] loadKeyManagers(QuickServerConfig config) throws GeneralSecurityException, IOException {
    Secure secure = config.getSecure();
    SecureStore secureStore = secure.getSecureStore();
    
    if (secureStore == null) {
      logger.fine("SecureStore configuration not set! So returning null for KeyManager");
      
      return null;
    } 
    
    KeyStoreInfo keyStoreInfo = secureStore.getKeyStoreInfo();
    if (keyStoreInfo == null) {
      logger.fine("KeyStoreInfo configuration not set! So returning null for KeyManager");
      
      return null;
    } 
    
    logger.finest("Loading KeyManagers");
    KeyStore ks = getKeyStoreForKey(secureStore.getType(), 
        secureStore.getProvider());
    
    char[] storepass = null;
    if (keyStoreInfo.getStorePassword() != null) {
      logger.finest("KeyStore: Store password was present!");
      storepass = keyStoreInfo.getStorePassword().toCharArray();
    } else {
      logger.finest("KeyStore: Store password was not set.. so asking!");
      if (this.sensitiveInput == null) {
        this.sensitiveInput = new SensitiveInput(String.valueOf(config.getName()) + " - Input Prompt");
      }
      storepass = this.sensitiveInput.getInput("Store password for KeyStore");
      if (storepass == null) {
        logger.finest("No password entered.. will pass null");
      }
    } 
    
    InputStream keyStoreStream = null;
    try {
      if (!keyStoreInfo.getStoreFile().equalsIgnoreCase("none")) {
        logger.finest("KeyStore location: " + 
            ConfigReader.makeAbsoluteToConfig(keyStoreInfo.getStoreFile(), 
              config));
        keyStoreStream = new FileInputStream(
            ConfigReader.makeAbsoluteToConfig(keyStoreInfo.getStoreFile(), 
              config));
      } 
      
      ks.load(keyStoreStream, storepass);
      logger.finest("KeyStore loaded");
    } finally {
      if (keyStoreStream != null) {
        keyStoreStream.close();
        keyStoreStream = null;
      } 
    } 
    
    char[] keypass = null;
    if (keyStoreInfo.getKeyPassword() != null) {
      logger.finest("KeyStore: key password was present!");
      keypass = keyStoreInfo.getKeyPassword().toCharArray();
    } else {
      logger.finest("KeyStore: Key password was not set.. so asking!");
      if (this.sensitiveInput == null) {
        this.sensitiveInput = new SensitiveInput(String.valueOf(config.getName()) + " - Input Prompt");
      }
      keypass = this.sensitiveInput.getInput("Key password for KeyStore");
      if (keypass == null) {
        logger.finest("No password entered.. will pass blank");
        keypass = "".toCharArray();
      } 
    } 
    
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(
        secureStore.getAlgorithm());
    kmf.init(ks, keypass);
    
    storepass = "               ".toCharArray();
    storepass = null;
    keypass = "               ".toCharArray();
    keypass = null;
    
    return kmf.getKeyManagers();
  }







  
  public TrustManager[] loadTrustManagers(QuickServerConfig config) throws GeneralSecurityException, IOException {
    Secure secure = config.getSecure();
    SecureStore secureStore = secure.getSecureStore();
    TrustStoreInfo trustStoreInfo = secureStore.getTrustStoreInfo();
    
    if (trustStoreInfo == null) {
      return null;
    }
    
    logger.finest("Loading TrustManagers");
    
    String type = null;
    if (trustStoreInfo.getType() != null && trustStoreInfo.getType().trim().length() != 0) {
      type = trustStoreInfo.getType();
    } else {
      type = secureStore.getType();
    } 
    String provider = null;
    if (trustStoreInfo.getProvider() != null && trustStoreInfo.getProvider().trim().length() != 0) {
      provider = trustStoreInfo.getProvider();
    } else {
      provider = secureStore.getProvider();
    } 
    KeyStore ts = getKeyStoreForTrust(type, provider);
    
    char[] trustpass = null;
    if (trustStoreInfo.getStorePassword() != null) {
      logger.finest("TrustStore: Store password was present!");
      trustpass = trustStoreInfo.getStorePassword().toCharArray();
    } else {
      logger.finest("TrustStore: Store password was not set.. so asking!");
      if (this.sensitiveInput == null) {
        this.sensitiveInput = new SensitiveInput(String.valueOf(config.getName()) + " - Input Prompt");
      }
      trustpass = this.sensitiveInput.getInput("Store password for TrustStore");
      if (trustpass == null) {
        logger.finest("No password entered.. will pass null");
      }
    } 
    
    InputStream trustStoreStream = null;
    try {
      if (!trustStoreInfo.getStoreFile().equalsIgnoreCase("none")) {
        logger.finest("TrustStore location: " + 
            ConfigReader.makeAbsoluteToConfig(
              trustStoreInfo.getStoreFile(), config));
        trustStoreStream = new FileInputStream(
            ConfigReader.makeAbsoluteToConfig(
              trustStoreInfo.getStoreFile(), config));
      } 
      
      ts.load(trustStoreStream, trustpass);
      logger.finest("TrustStore loaded");
    } finally {
      if (trustStoreStream != null) {
        trustStoreStream.close();
        trustStoreStream = null;
      } 
    } 
    
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(
        secureStore.getAlgorithm());
    tmf.init(ts);
    return tmf.getTrustManagers();
  }






  
  public SSLContext getSSLContext(String protocol) throws NoSuchAlgorithmException { return SSLContext.getInstance(protocol); }










  
  protected KeyStore getKeyStoreForKey(String type, String provider) throws KeyStoreException, NoSuchProviderException {
    if (provider == null)
      return KeyStore.getInstance(type); 
    return KeyStore.getInstance(type, provider);
  }










  
  protected KeyStore getKeyStoreForTrust(String type, String provider) throws KeyStoreException, NoSuchProviderException {
    if (provider == null)
      return KeyStore.getInstance(type); 
    return KeyStore.getInstance(type, provider);
  }




  
  public SSLSocketFactory getSocketFactory(SSLContext context) { return context.getSocketFactory(); }






  
  public void logSSLServerSocketInfo(SSLServerSocket sslServerSocket) {
    if (!logger.isLoggable(Level.FINEST)) {
      return;
    }
    logger.finest("SecureServer Info: ClientAuth: " + 
        sslServerSocket.getNeedClientAuth());
    logger.finest("SecureServer Info: ClientMode: " + 
        sslServerSocket.getUseClientMode());
    
    String[] supportedSuites = sslServerSocket.getSupportedCipherSuites();
    logger.finest("SecureServer Info: Supported Cipher Suites --------");
    for (int i = 0; i < supportedSuites.length; i++)
      logger.finest(supportedSuites[i]); 
    logger.finest("---------------------------------------------------");
    
    String[] enabledSuites = sslServerSocket.getEnabledCipherSuites();
    logger.finest("SecureServer Info: Enabled Cipher Suites ----------");
    for (int i = 0; i < enabledSuites.length; i++)
      logger.finest(enabledSuites[i]); 
    logger.finest("---------------------------------------------------");

    
    String[] supportedProtocols = sslServerSocket.getSupportedProtocols();
    logger.finest("SecureServer Info: Supported Protocols ------------");
    for (int i = 0; i < supportedProtocols.length; i++)
      logger.finest(supportedProtocols[i]); 
    logger.finest("---------------------------------------------------");
    
    String[] enabledProtocols = sslServerSocket.getEnabledProtocols();
    logger.finest("SecureServer Info: Enabled Protocols --------------");
    for (int i = 0; i < enabledProtocols.length; i++)
      logger.finest(enabledProtocols[i]); 
    logger.finest("---------------------------------------------------");
  }
}
